package net.boot.smpp.listener;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import net.boot.smpp.service.MessageGatewayService;
import net.boot.smpp.task.SmppPoolTask;
import org.jsmpp.SMPPConstant;
import org.jsmpp.bean.*;
import org.jsmpp.extra.ProcessRequestException;
import org.jsmpp.session.*;
import org.jsmpp.util.*;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * SMPP 服务器监听器，用于接收和处理 SMPP 连接
 * @author qiusu
 * @since  2025/08/18
 */
@Slf4j
@Component
public class SmppListener implements ServerMessageReceiverListener {
    private static final String CANCELSM_NOT_IMPLEMENTED = "cancel_sm not implemented";
    private static final String REPLACESM_NOT_IMPLEMENTED = "replace_sm not implemented";

    private final MessageIDGenerator messageIDGenerator = new RandomMessageIDGenerator();
    private final AbsoluteTimeFormatter timeFormatter = new AbsoluteTimeFormatter();
    private final AtomicInteger requestCounter = new AtomicInteger();

    @Resource
    private SmppPoolTask smppPoolTask;
    @Resource
    private MessageGatewayService messageGatewayService;

    @Override
    public QuerySmResult onAcceptQuerySm(QuerySm querySm,
                                         SMPPServerSession source) throws ProcessRequestException {
        String finalDate = timeFormatter.format(new Date());
        log.info("Receiving query_sm, and return {}", finalDate);
        return new QuerySmResult(finalDate, MessageState.DELIVERED, (byte)0x00);
    }

    @Override
    public SubmitSmResult onAcceptSubmitSm(SubmitSm submitSm,
                                           SMPPServerSession source) throws ProcessRequestException {
        MessageId messageId = messageIDGenerator.newMessageId();
        byte[] shortMessage = submitSm.getShortMessage();
        String message = "";
        if (submitSm.isUdhi()) {
            int udhl = (shortMessage[0] & 0xff);
            message = new String(shortMessage, 1+udhl,shortMessage.length - udhl - 1);
            log.info("Receiving submit_sm {} {}, return message id {}",
                    HexUtil.convertBytesToHexString(shortMessage, 0, 1 + udhl),
                    message,
                    messageId.getValue());
        } else {
            message = new String(submitSm.getShortMessage());
            log.info("Receiving submit_sm {}, return message id {}",message, messageId.getValue());
        }

        try {
            messageGatewayService.business(submitSm.getDestAddress(), message);
        } catch (Exception e) {
            log.error("messageGatewayService.business方法业务功能异常 {}",e.getMessage());
        }

        requestCounter.incrementAndGet();

        if (SMSCDeliveryReceipt.SUCCESS_FAILURE.containedIn(submitSm.getRegisteredDelivery())) {
            log.debug("Schedule delivery receipt in 1000ms");
            //deliveryExecService.schedule(new DeliveryReceiptTask(source, submitSm, messageId), 1000, TimeUnit.MILLISECONDS);
            smppPoolTask.deliveryReceiptTask(source, submitSm, messageId);
        }

        return new SubmitSmResult(messageId, new OptionalParameter[0]);
    }

    @Override
    public SubmitMultiResult onAcceptSubmitMulti(SubmitMulti submitMulti,
                                                 SMPPServerSession source) throws ProcessRequestException {
        MessageId messageId = messageIDGenerator.newMessageId();
        log.info("Receiving submit_multi {}, and return message id {}", new String(submitMulti.getShortMessage()), messageId.getValue());
        requestCounter.incrementAndGet();
        return new SubmitMultiResult(messageId.getValue(), new UnsuccessDelivery[0], new OptionalParameter[0]);
    }

    @Override
    public DataSmResult onAcceptDataSm(DataSm dataSm, Session source)
            throws ProcessRequestException {
        MessageId messageId = messageIDGenerator.newMessageId();
        OptionalParameter.Message_payload messagePayload = (OptionalParameter.Message_payload)dataSm.getOptionalParameter(OptionalParameter.Tag.MESSAGE_PAYLOAD);
        log.info("Receiving data_sm {}, and return message id {}", messagePayload.getValueAsString(), messageId.getValue());
        requestCounter.incrementAndGet();
        return new DataSmResult(messageId, new OptionalParameter[]{});
    }

    @Override
    public void onAcceptCancelSm(CancelSm cancelSm, SMPPServerSession source)
            throws ProcessRequestException {
        log.warn("cancel_sm not implemented");
        throw new ProcessRequestException(CANCELSM_NOT_IMPLEMENTED, SMPPConstant.STAT_ESME_RCANCELFAIL);
    }

    @Override
    public void onAcceptReplaceSm(ReplaceSm replaceSm, SMPPServerSession source)
            throws ProcessRequestException {
        log.warn("replace_sm not implemented");
        throw new ProcessRequestException(REPLACESM_NOT_IMPLEMENTED, SMPPConstant.STAT_ESME_RREPLACEFAIL);
    }

    @Override
    public BroadcastSmResult onAcceptBroadcastSm(final BroadcastSm broadcastSm, final SMPPServerSession source)
            throws ProcessRequestException {
        MessageId messageId = messageIDGenerator.newMessageId();
        OptionalParameter[] optionalParameters = new OptionalParameter[]{};
        log.info("Received broadcast_sm, and return {}", messageId);
        return new BroadcastSmResult(messageId, optionalParameters);
    }

    @Override
    public void onAcceptCancelBroadcastSm(final CancelBroadcastSm cancelBroadcastSm, final SMPPServerSession source)
            throws ProcessRequestException {
        log.info("Received cancel_broadcast_sm");
    }

    @Override
    public QueryBroadcastSmResult onAcceptQueryBroadcastSm(final QueryBroadcastSm queryBroadcastSm,
                                                           final SMPPServerSession source) throws ProcessRequestException {
        MessageId messageId = messageIDGenerator.newMessageId();
        OptionalParameter[] optionalParameters = new OptionalParameter[]{};
        log.info("Receiving query_broadcast_sm, and return {}", messageId);
        return new QueryBroadcastSmResult(messageId, optionalParameters);
    }

}
